import * as WebIFC from 'web-ifc'

export class IfcService {
  viewer = null
  currentModelId = null // 保存当前加载的模型ID
  highlightGroup = null // 边框高亮组
  edgeMaterial = null // 复用的边框材质
  currentHighlightedIds = new Set() // 当前高亮的 expressID 集合
  meshCache = new Map() // expressID -> mesh 的缓存
  highlightEnabled = false // 是否允许高亮（默认关闭）
  
  constructor(viewer) {
    this.viewer = viewer
  }
  
  /**
   * 设置是否允许高亮
   * @param {boolean} enabled - 是否允许高亮
   */
  setHighlightEnabled(enabled) {
    this.highlightEnabled = enabled
    
    if (enabled) {
      // 如果启用高亮，启用选择模式
      this.enableSelectionMode()
    } else {
      // 如果禁用高亮，清除所有当前高亮
      this.clearAllHighlights()
    }
    
    console.log(`高亮功能已${enabled ? '启用' : '禁用'}`)
  }
  
  /**
   * 清除所有高亮（边框高亮、材质高亮、选择高亮等）
   */
  clearAllHighlights() {
    // 1. 清除边框高亮
    this.clearHighlightEdges()
    
    // 2. 清除材质高亮（恢复原始材质）
    if (this.viewer) {
      try {
        const viewer = this.viewer
        const scene = viewer.context?.getScene()
        
        if (scene) {
          scene.traverse((child) => {
            if (child.userData && child.userData.isHighlighted) {
              // 恢复原始材质
              if (child.userData.originalMaterial) {
                child.material = child.userData.originalMaterial
                child.userData.originalMaterial = null
              }
              child.userData.isHighlighted = false
            }
          })
        }
      } catch (err) {
        console.warn('清除材质高亮失败:', err)
      }
    }
    
    // 3. 清除 web-ifc-viewer 的高亮
    if (this.viewer && this.currentModelId !== null) {
      try {
        if (this.viewer.removeHighlight) {
          this.viewer.removeHighlight(this.currentModelId)
        }
      } catch (err) {
        // 忽略错误
      }
    }
    
    // 4. 清除选择模式的高亮
    if (this.viewer) {
      try {
        const ifcManager = this.viewer.IFC
        if (ifcManager && ifcManager.selector) {
          // 尝试多种清除方法
          const clearMethods = [
            () => ifcManager.selector.unhighlight?.(),
            () => ifcManager.selector.unselect?.(),
            () => ifcManager.unhighlight?.(),
            () => ifcManager.unselect?.(),
            () => ifcManager.selector.clearSelection?.(),
            () => this.clearSelection()
          ]
          
          for (const method of clearMethods) {
            try {
              method()
            } catch (err) {
              // 继续尝试下一个方法
            }
          }
        }
      } catch (err) {
        console.warn('清除选择高亮失败:', err)
      }
    }
    
    console.log('✓ 已清除所有高亮')
  }
  
  /**
   * 获取是否允许高亮
   * @returns {boolean} 是否允许高亮
   */
  isHighlightEnabled() {
    return this.highlightEnabled
  }
  
  async waitForIfcManager() {
    if (!this.viewer) {
      throw new Error('IFC viewer 未初始化')
    }
    
    const viewer = this.viewer
    const retryDelay = 50 // 每 50ms 检查一次
    
    console.log('等待 IFC 管理器初始化...')
    
    // 无限循环检查，直到真正就绪
    while (true) {
      const ifcManager = viewer.IFC
      
      // 检查 IFC 管理器是否存在且方法可用
      if (ifcManager) {
        // 检查 loadIfcFile 方法是否可用（这是核心方法）
        if (ifcManager.loadIfcFile && typeof ifcManager.loadIfcFile === 'function') {
          console.log('✓ IFC 管理器已完全就绪，loadIfcFile 方法可用')
          return ifcManager
        }
        
        // 如果存在但方法不可用，继续等待（可能是 WASM 还在加载）
        console.log('IFC 管理器存在，等待 loadIfcFile 方法就绪...')
      } else {
        // IFC 管理器还不存在，继续等待
        console.log('等待 IFC 管理器出现...')
      }
      
      // 短暂等待后再次检查
      await new Promise(resolve => setTimeout(resolve, retryDelay))
    }
  }
  
  clearModel() {
    if (!this.viewer) return
    
    try {
      // 清除边框高亮
      this.clearHighlightEdges()
      
      // 清除缓存
      this.meshCache.clear()
      
      // 清除材质
      if (this.edgeMaterial) {
        this.edgeMaterial.dispose()
        this.edgeMaterial = null
      }
      
      // 清除 web-ifc-viewer 的高亮（如果存在）
      if (this.currentModelId !== null && this.viewer.removeHighlight) {
        try {
          this.viewer.removeHighlight(this.currentModelId)
        } catch (err) {
          // 忽略
        }
      }
      
      console.log('=== 开始清除旧模型 ===')
      const viewer = this.viewer
      const scene = viewer.context?.getScene()
      
      if (!scene) {
        console.warn('场景不存在，无法清除')
        return
      }
      
      // 方法1：使用 IFC 管理器的清除方法（优先）
      const ifcManager = viewer.IFC
      if (ifcManager) {
        console.log('尝试使用 IFC 管理器清除方法...')
        
        // 尝试获取并移除所有模型 ID
        try {
          // 检查是否有 getAllModelIDs 或 getModelIds 方法
          const getModelIds = ifcManager.getAllModelIDs || 
                             ifcManager.getModelIds || 
                             ifcManager.getModels
          
          if (getModelIds && typeof getModelIds === 'function') {
            const modelIds = getModelIds()
            console.log('找到模型 ID:', modelIds)
            
            if (Array.isArray(modelIds) && modelIds.length > 0) {
              // 如果有 removeModel 方法，逐个移除
              if (ifcManager.removeModel && typeof ifcManager.removeModel === 'function') {
                modelIds.forEach((id) => {
                  try {
                    console.log(`移除模型 ID: ${id}`)
                    ifcManager.removeModel(id)
                  } catch (err) {
                    console.warn(`移除模型 ${id} 失败:`, err)
                  }
                })
              }
              
              // 如果有 closeModel 方法，逐个关闭
              if (ifcManager.closeModel && typeof ifcManager.closeModel === 'function') {
                modelIds.forEach((id) => {
                  try {
                    console.log(`关闭模型 ID: ${id}`)
                    ifcManager.closeModel(id)
                  } catch (err) {
                    console.warn(`关闭模型 ${id} 失败:`, err)
                  }
                })
              }
            }
          }
        } catch (err) {
          console.warn('获取模型 ID 失败:', err)
        }
        
        // 尝试使用 close 方法关闭所有模型
        if (ifcManager.close && typeof ifcManager.close === 'function') {
          try {
            console.log('调用 IFC close 方法...')
            ifcManager.close()
          } catch (err) {
            console.warn('IFC close 方法失败:', err)
          }
        }
        
        // 清除选择和高亮
        if (ifcManager.selector) {
          try {
            if (ifcManager.selector.unpick) {
              ifcManager.selector.unpick()
            }
            if (ifcManager.selector.unhighlight) {
              ifcManager.selector.unhighlight()
            }
          } catch (err) {
            console.warn('清除选择失败:', err)
          }
        }
      }
      
      // 方法2：直接从场景中移除所有 IFC 相关对象
      console.log('从场景中移除 IFC 对象...')
      const childrenToRemove = []
      
      // 先收集所有需要移除的对象（避免遍历时删除）
      scene.traverse((child) => {
        // 检查是否是 IFC 模型对象
        if (child.userData) {
          const hasIfcData = child.userData.expressID || 
                           child.userData.ifcClass || 
                           child.userData.modelID ||
                           child.userData.category === 'IFC' ||
                           child.name?.includes('IFC') ||
                           child.name?.includes('Ifc')
          
          if (hasIfcData) {
            childrenToRemove.push({
              child: child,
              parent: child.parent,
              type: child.type,
              name: child.name || 'unknown'
            })
          }
        }
      })
      
      console.log(`找到 ${childrenToRemove.length} 个 IFC 对象需要移除`)
      
      // 移除所有收集到的对象
      childrenToRemove.forEach(({ child, parent, type, name }) => {
        try {
          if (parent) {
            parent.remove(child)
            console.log(`移除对象: ${name} (${type})`)
          }
          
          // 如果对象有 dispose 方法，调用它释放资源
          if (child.dispose && typeof child.dispose === 'function') {
            try {
              child.dispose()
            } catch (err) {
              // 忽略 dispose 错误
            }
          }
          
          // 清除几何体和材质
          if (child.geometry) {
            try {
              if (child.geometry.dispose) {
                child.geometry.dispose()
              }
            } catch (err) {
              // 忽略几何体清除错误
            }
          }
          
          if (child.material) {
            try {
              if (Array.isArray(child.material)) {
                  child.material.forEach((mat) => {
                  if (mat && mat.dispose) {
                    mat.dispose()
                  }
                })
              } else if (child.material.dispose) {
                child.material.dispose()
              }
            } catch (err) {
              // 忽略材质清除错误
            }
          }
        } catch (err) {
          console.warn(`移除对象 ${name} 失败:`, err)
        }
      })
      
      // 方法3：清除场景中所有非必要的子对象（更激进的方法）
      // 只保留 axes 和 grid 等基础对象
      try {
        const sceneChildren = [...(scene.children || [])]
        let removedCount = 0
        
        sceneChildren.forEach((child) => {
          // 检查是否是需要保留的基础对象
          const isBaseObject = child.name && (
            child.name.includes('Axes') || 
            child.name.includes('Grid') ||
            child.name.includes('Camera') ||
            child.name.includes('Light')
          )
          
          // 如果不是基础对象，且有 IFC 相关数据，则移除
          if (!isBaseObject) {
            const hasIfcData = child.userData && (
              child.userData.expressID || 
              child.userData.ifcClass ||
              child.userData.modelID ||
              child.userData.category === 'IFC'
            )
            
            // 或者没有用户数据，但可能是 IFC 模型的一部分（通过类型判断）
            const isMeshObject = child.type === 'Mesh' || child.type === 'Group' || child.type === 'Object3D'
            
            if (hasIfcData || (isMeshObject && !child.userData?.isBase)) {
              try {
                // 先清理子对象
                if (child.children && child.children.length > 0) {
                  const subChildren = [...child.children]
                  subChildren.forEach((subChild) => {
                    try {
                      if (subChild.geometry) {
                        subChild.geometry.dispose?.()
                      }
                      if (subChild.material) {
                        if (Array.isArray(subChild.material)) {
                          subChild.material.forEach((mat) => mat?.dispose?.())
                        } else {
                          subChild.material.dispose?.()
                        }
                      }
                      subChild.dispose?.()
                    } catch (err) {
                      // 忽略子对象清理错误
                    }
                  })
                }
                
                // 清理对象本身
                if (child.geometry) {
                  child.geometry.dispose?.()
                }
                if (child.material) {
                  if (Array.isArray(child.material)) {
                    child.material.forEach((mat) => mat?.dispose?.())
                  } else {
                    child.material.dispose?.()
                  }
                }
                
                // 从场景移除
                scene.remove(child)
                removedCount++
                console.log(`从场景移除: ${child.name || child.type || 'unnamed'}`)
              } catch (err) {
                console.warn(`移除场景子对象失败 (${child.name || 'unnamed'}):`, err)
              }
            }
          }
        })
        
        console.log(`共移除了 ${removedCount} 个场景对象`)
      } catch (err) {
        console.warn('清理场景子对象失败:', err)
      }
      
      // 方法4：尝试重置 IFC 管理器状态
      if (ifcManager) {
        try {
          // 重置所有模型状态
          if (ifcManager.reset && typeof ifcManager.reset === 'function') {
            console.log('调用 IFC reset 方法...')
            ifcManager.reset()
          }
        } catch (err) {
          console.warn('IFC reset 失败:', err)
        }
      }
      
      // 强制更新场景渲染
      try {
        if (viewer.context?.renderer?.render) {
          viewer.context.renderer.render(scene, viewer.context.ifcCamera?.camera)
        }
      } catch (err) {
        console.warn('更新渲染失败:', err)
      }
      
      // 清除保存的 modelId
      this.currentModelId = null
      
      console.log('✓ 旧模型清除完成')
    } catch (err) {
      console.error('清除模型失败:', err)
      // 不抛出错误，继续尝试加载新模型
    }
  }
  
  async loadIfcFile(file) {
    if (!this.viewer) {
      throw new Error('IFC viewer 未初始化')
    }
    
    try {
      // 先清除旧模型
      this.clearModel()
      
      // 等待清除操作完成（给一点时间让清除操作生效）
      await new Promise(resolve => setTimeout(resolve, 200))
      
      console.log('等待 IFC 管理器就绪...')
      const ifcManager = await this.waitForIfcManager()
      
      console.log('开始加载 IFC 文件:', file.name, '大小:', file.size, 'bytes')
      
      if (ifcManager.loadIfcFile) {
        // loadIfcFile 可能返回 modelId（根据官方文档）
        const result = await ifcManager.loadIfcFile(file, true)
        console.log('IFC 文件加载完成，返回结果:', result)
        
        // 尝试从返回值中获取 modelId
        if (result !== undefined && result !== null) {
          if (typeof result === 'object' && result.modelId !== undefined) {
            this.currentModelId = result.id
            console.log('✅ 从 loadIfcFile 返回值对象获取 modelId:', result.id)
          } else if (typeof result === 'number') {
            this.currentModelId = result
            console.log('✅ 从 loadIfcFile 返回值获取 modelId:', result)
          }
        }
        
        // 等待模型完全加载（文档要求）
        await new Promise(resolve => setTimeout(resolve, 500))
        
        // 如果允许高亮，启用选择模式（文档要求）
        if (this.highlightEnabled) {
          this.enableSelectionMode()
        }
      } else {
        throw new Error('IFC 管理器缺少 loadIfcFile 方法')
      }
    } catch (err) {
      const errorMsg = err.message || err.toString() || 'IFC 文件加载失败'
      console.error('loadIfcFile 错误:', err)
      throw new Error(`加载 IFC 文件失败: ${errorMsg}`)
    }
  }
  
  async loadIfcUrl(url) {
    if (!this.viewer) {
      throw new Error('IFC viewer 未初始化')
    }
    
    // 方法1：先下载文件，然后使用 loadIfcFile（推荐，可处理 CORS 问题）
    try {
      console.log('使用方案1：先下载文件再加载')
      
      // 检查 URL 是否可访问
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'Accept': 'application/octet-stream, application/ifc, text/plain, */*'
        }
      })
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`)
      }
      
      // 检查 Content-Type
      const contentType = response.headers.get('content-type') || ''
      console.log('响应 Content-Type:', contentType)
      
      // 下载文件
      const blob = await response.blob()
      console.log('文件下载成功，大小:', blob.size, 'bytes')
      
      if (blob.size === 0) {
        throw new Error('下载的文件为空')
      }
      
      // 创建 File 对象
      const fileName = url.split('/').pop() || 'model.ifc'
      const file = new File([blob], fileName, { 
        type: blob.type || 'application/octet-stream' 
      })
      
      // 使用 loadIfcFile 加载
      console.log('开始加载 IFC 文件...')
      await this.loadIfcFile(file)
      console.log('IFC 文件加载成功')
      return
      
    } catch (err) {
      console.warn('方案1失败，尝试直接加载 URL:', err)
      
      // 方法2：直接使用 loadIfcUrl（备用方案）
      try {
        const ifcManager = await this.waitForIfcManager()
        
        if (ifcManager.loadIfcUrl) {
          console.log('尝试直接加载 URL:', url)
          await ifcManager.loadIfcUrl(url)
          console.log('URL 直接加载成功')
          return
        } else {
          throw new Error('IFC 管理器不支持 loadIfcUrl 方法')
        }
      } catch (err2) {
        const errorMsg = err.message || err2.message || 'IFC URL 加载失败'
        console.error('loadIfcUrl 所有方法都失败:', err2)
        throw new Error(`从 URL 加载 IFC 失败: ${errorMsg}`)
      }
    }
  }
  
  async getModelItems() {
    if (!this.viewer) {
      console.warn('Viewer 未初始化')
      return []
    }
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      
      if (!ifcManager) {
        console.warn('IFC 管理器不存在')
        return []
      }
      
      console.log('开始获取模型数据...')
      console.log('IFC 管理器:', ifcManager)
      console.log('IFC 管理器的键:', Object.keys(ifcManager))
      
      // 方法1：优先使用 getSpatialStructure API（官方推荐方法）
      try {
        // 尝试多种方式获取模型 ID
        let modelIds = []
        
        const possibleMethods = [
          () => ifcManager.getAllModelIDs?.(),
          () => ifcManager.getModelIds?.(),
          () => ifcManager.getModels?.(),
          () => ifcManager.models,
          () => {
            const scenes = ifcManager.scenes || ifcManager.loader?.scenes
            if (scenes && Array.isArray(scenes)) {
              return scenes.map(s => s.modelID || s.id).filter(id => id != null)
            }
            return null
          }
        ]
        
        for (const method of possibleMethods) {
          try {
            const result = method()
            if (result) {
              if (Array.isArray(result)) {
                modelIds = result.filter((id) => id != null && typeof id === 'number')
              } else if (typeof result === 'number') {
                modelIds = [result]
              }
              if (modelIds.length > 0) break
            }
          } catch (err) {
            // 忽略单个方法错误
          }
        }
        
        // 如果找不到模型 ID，尝试使用 0
        if (modelIds.length === 0) {
          console.log('未找到模型 ID，尝试使用默认模型 ID: 0')
          modelIds = [0]
        }
        
        console.log('找到模型 ID:', modelIds)
        
        // 尝试使用 getSpatialStructure 获取结构
        if (ifcManager.getSpatialStructure && typeof ifcManager.getSpatialStructure === 'function') {
          console.log('尝试使用 getSpatialStructure API...')
          
          for (const modelID of modelIds) {
            try {
              const structure = await ifcManager.getSpatialStructure(modelID, true) // 包含属性
              console.log('getSpatialStructure 返回:', structure)
              
              if (structure) {
                // 转换结构为树形数据
                const treeData = this.convertSpatialStructureToTree(structure)
                if (treeData && treeData.length > 0) {
                  console.log(`成功通过 getSpatialStructure 获取 ${treeData.length} 个项目`)
                  return treeData
                }
              }
            } catch (err) {
              console.warn(`getSpatialStructure 失败 (模型 ${modelID}):`, err)
            }
          }
        } else {
          console.warn('getSpatialStructure 方法不存在')
        }
      } catch (err) {
        console.error('使用 getSpatialStructure 失败:', err)
      }
      
      // 方法2：使用 IFC API 手动构建（备用方法）
      const ifcAPI = ifcManager.ifcAPI || ifcManager.api || ifcManager.ifcApi
      
      if (ifcAPI) {
        console.log('尝试使用 IFC API 手动构建...')
        
        let modelIds = []
        
        // 尝试获取模型 ID
        const possibleMethods = [
          () => ifcManager.getAllModelIDs?.(),
          () => ifcManager.getModelIds?.(),
          () => [0] // 默认使用 0
        ]
        
        for (const method of possibleMethods) {
          try {
            const result = method()
            if (result && Array.isArray(result)) {
              modelIds = result.filter(id => id != null && typeof id === 'number')
              if (modelIds.length > 0) break
            }
          } catch (err) {
            // 忽略错误
          }
        }
        
        if (modelIds.length === 0) {
          modelIds = [0]
        }
        
        const items = []
        
        for (const modelID of modelIds) {
          try {
            console.log(`处理模型 ID: ${modelID}`)
            const modelItems = this.getAllElementsFromModel(modelID, ifcAPI)
            items.push(...modelItems)
          } catch (err) {
            console.error(`处理模型 ${modelID} 失败:`, err)
          }
        }
        
        if (items.length > 0) {
          console.log(`通过 IFC API 获取到 ${items.length} 个顶层项目`)
          return items
        }
      }
      
      // 方法3：从场景获取（最后备用方法）
      console.log('从场景获取数据...')
      return this.getModelItemsFromScene()
      
    } catch (err) {
      console.error('获取模型数据失败:', err)
      return this.getModelItemsFromScene()
    }
  }
  
  // 将 getSpatialStructure 返回的结构转换为树形数据，并为 Storey 下的元素添加 IFC 类型层级
  convertSpatialStructureToTree(structure) {
    try {
      if (!structure) return []
      
      // structure 可能是节点对象，需要递归转换
      const self = this
      function convertNode(node) {
        if (!node) return null
        
        // 优先使用 value 属性作为名称
        // value 可能是字符串，直接使用；如果是对象，尝试获取其 value 属性
        let nodeName = ''
        
        if (node.value !== undefined && node.value !== null) {
          if (typeof node.value === 'string') {
            nodeName = node.value
          } else if (typeof node.value === 'object') {
            // 如果是对象，尝试获取其 value 或其他属性
            nodeName = node.value.value || node.value.Name || node.value.name || String(node.value)
          } else {
            nodeName = String(node.value)
          }
        } else if (node.Value !== undefined && node.Value !== null) {
          nodeName = typeof node.Value === 'string' ? node.Value : String(node.Value)
        } else {
          // 回退到其他属性
          nodeName = node.name || node.Name || node.type || node.Type || 'Unknown'
        }
        
        const nodeType = node.type || node.Type || 'Unknown'
        const result = {
          expressID: node.expressID || node.ExpressID || 0,
          name: nodeName,
          type: nodeType,
          children: [],
          properties: node
        }
        
        // 对于 BuildingStorey，需要对其子元素按 IFC 类型分组，添加类型层级
        if (nodeType === 'IFCBuildingStorey' || nodeType === 'IFCBUILDINGSTOREY') {
          // 收集所有子元素
          const allChildren = []
          
          // 处理子节点
          if (node.children && Array.isArray(node.children)) {
            for (const child of node.children) {
              const convertedChild = convertNode(child)
              if (convertedChild) {
                allChildren.push(convertedChild)
              }
            }
          }
          
          // 处理相关元素
          if (node.childrenTypes) {
            for (const childType in node.childrenTypes) {
              const children = node.childrenTypes[childType]
              if (Array.isArray(children)) {
                for (const child of children) {
                  const convertedChild = convertNode(child)
                  if (convertedChild) {
                    allChildren.push(convertedChild)
                  }
                }
              }
            }
          }
          
          // 将子元素按 IFC 类型分组
          const elementsByType = new Map()
          const spaces = []
          
          for (const child of allChildren) {
            // Space 节点直接添加，不分组
            if (child.type === 'IFCSpace' || child.type === 'IFCSPACE') {
              spaces.push(child)
            } else {
              // 其他元素按 IFC 类型分组
              const ifcType = child.type || 'Unknown'
              if (!elementsByType.has(ifcType)) {
                elementsByType.set(ifcType, [])
              }
              if(elementsByType.get(ifcType)) {
                elementsByType.get(ifcType).push(child)
              }
            }
          }
          
          // 先添加 Space 节点
          result.children.push(...spaces)
          
          // 为每个 IFC 类型创建类型组节点
          for (const [ifcType, elements] of elementsByType) {
            if (elements.length > 0) {
              // 总是创建 IFC 类型组节点
              const typeGroupNode = {
                expressID: 0,
                name: ifcType,
                type: 'IFCCategory',
                children: elements,
                properties: {}
              }
              result.children.push(typeGroupNode)
              console.log(`[convertSpatialStructureToTree] 为楼层 ${nodeName} 创建 IFC 类型组: ${ifcType}, 包含 ${elements.length} 个子项`)
            }
          }
          
          console.log(`[convertSpatialStructureToTree] 楼层 ${nodeName} 共有 ${result.children.length} 个子节点（包括 ${elementsByType.size} 个类型组）`)
        } else {
          // 非 Storey 节点，正常处理子节点
          // 处理子节点
          if (node.children && Array.isArray(node.children)) {
            for (const child of node.children) {
              const convertedChild = convertNode(child)
              if (convertedChild) {
                result.children.push(convertedChild)
              }
            }
          }
          
          // 处理相关元素
          if (node.childrenTypes) {
            for (const childType in node.childrenTypes) {
              const children = node.childrenTypes[childType]
              if (Array.isArray(children)) {
                for (const child of children) {
                  const convertedChild = convertNode(child)
                  if (convertedChild) {
                    result.children.push(convertedChild)
                  }
                }
              }
            }
          }
        }
        
        return result
      }
      
      // 如果 structure 是数组
      if (Array.isArray(structure)) {
        return structure.map(node => convertNode(node)).filter(node => node !== null)
      }
      
      // 如果 structure 是单个节点
      const converted = convertNode(structure)
      return converted ? [converted] : []
      
    } catch (err) {
      console.error('转换空间结构失败:', err)
      return []
    }
  }
  
  getAllElementsFromModel(modelID, ifcAPI) {
    try {
      console.log(`从模型 ${modelID} 获取所有元素...`)
      
      // 优先尝试获取空间结构（Project -> Site -> Building -> Storeys）
      const projectIDs = ifcAPI.GetLineIDsWithType(modelID, WebIFC.IFCPROJECT)
      if (projectIDs && projectIDs.length > 0) {
        console.log(`找到 ${projectIDs.length} 个项目，尝试构建空间结构...`)
        const spatialStructure = this.buildSpatialStructure(modelID, ifcAPI)
        if (spatialStructure && spatialStructure.length > 0) {
          console.log('成功构建空间结构')
          return spatialStructure
        }
      }
      
      // 如果空间结构失败，使用标准结构
      console.log('空间结构为空，使用标准结构...')
      return this.buildIfcStandardStructure(modelID, ifcAPI)
      
    } catch (err) {
      console.error(`获取模型 ${modelID} 的元素失败:`, err)
      // 最后尝试获取所有元素
      try {
        return this.getAllElements(modelID, ifcAPI)
      } catch {
        return []
      }
    }
  }
  
  buildIfcStandardStructure(modelID, ifcAPI) {
    try {
      console.log('构建 IFC 标准结构树...')
      const rootItems = []
      
      // 1. 实体（Entities）- 实际的建筑元素
      const entitiesItem = {
        expressID: 0,
        name: '实体 (Entities)',
        type: 'IFCCategory',
        children: this.getEntities(modelID, ifcAPI)
      }
      
      // 2. 类型（Types）- IFC 类型对象
      const typesItem = {
        expressID: 0,
        name: '类型 (Types)',
        type: 'IFCCategory',
        children: this.getTypes(modelID, ifcAPI)
      }
      
      // 3. 属性集（Property Sets）
      const propertySetsItem = {
        expressID: 0,
        name: '属性集 (Property Sets)',
        type: 'IFCCategory',
        children: this.getPropertySets(modelID, ifcAPI)
      }
      
      // 4. 量集（Quantity Sets）
      const quantitySetsItem = {
        expressID: 0,
        name: '量集 (Quantity Sets)',
        type: 'IFCCategory',
        children: this.getQuantitySets(modelID, ifcAPI)
      }
      
      // 5. 规则（Rules）
      const rulesItem = {
        expressID: 0,
        name: '规则 (Rules)',
        type: 'IFCCategory',
        children: this.getRules(modelID, ifcAPI)
      }
      
      // 6. 函数（Functions）- IFC 中可能没有直接概念，但可以包含计算方法
      const functionsItem = {
        expressID: 0,
        name: '函数 (Functions)',
        type: 'IFCCategory',
        children: this.getFunctions(modelID, ifcAPI)
      }
      
      // 只添加有子节点的分类
      if (entitiesItem.children.length > 0) {
        rootItems.push(entitiesItem)
      }
      if (typesItem.children.length > 0) {
        rootItems.push(typesItem)
      }
      if (propertySetsItem.children.length > 0) {
        rootItems.push(propertySetsItem)
      }
      if (quantitySetsItem.children.length > 0) {
        rootItems.push(quantitySetsItem)
      }
      if (rulesItem.children.length > 0) {
        rootItems.push(rulesItem)
      }
      if (functionsItem.children.length > 0) {
        rootItems.push(functionsItem)
      }
      
      console.log(`构建完成，共 ${rootItems.length} 个主要分类`)
      return rootItems.length > 0 ? rootItems : this.getAllElements(modelID, ifcAPI)
      
    } catch (err) {
      console.error('构建 IFC 标准结构失败:', err)
      return this.getAllElements(modelID, ifcAPI)
    }
  }
  
  getEntities(modelID, ifcAPI) {
    try {
      console.log('获取实体（Entities）...')
      const items = []
      
      // 获取空间结构
      const projectIDs = ifcAPI.GetLineIDsWithType(modelID, WebIFC.IFCPROJECT)
      if (projectIDs && projectIDs.length > 0) {
        const spatialItems = this.buildSpatialStructure(modelID, ifcAPI)
        items.push(...spatialItems)
      }
      
      // 获取所有建筑元素实体
      const entityTypes = [
        WebIFC.IFCWALL,
        WebIFC.IFCWALLSTANDARDCASE,
        WebIFC.IFCSLAB,
        WebIFC.IFCROOF,
        WebIFC.IFCDOOR,
        WebIFC.IFCWINDOW,
        WebIFC.IFCCOLUMN,
        WebIFC.IFCBEAM,
        WebIFC.IFCSTAIR,
        WebIFC.IFCBUILDINGELEMENTPROXY,
        WebIFC.IFCPRODUCT
      ]
      
      const existingIDs = new Set()
      // 从空间结构中收集已有的 ID
      items.forEach(item => {
        this.collectIDs(item, existingIDs)
      })
      
      // 获取其他实体
      for (const entityType of entityTypes) {
        try {
          const entityIDs = ifcAPI.GetLineIDsWithType(modelID, entityType)
          if (!entityIDs || entityIDs.length === 0) continue
          
          const typeName = this.getTypeName(entityType)
          const typeGroup = []
          
          for (const entityID of entityIDs) {
            if (existingIDs.has(entityID)) continue // 跳过已在空间结构中的元素
            
            try {
              const entity = ifcAPI.GetLine(modelID, entityID)
              // 优先使用 value 属性
              const name = this.getPropertyValue(entity, 'value') ||
                          this.getPropertyValue(entity, 'Value') ||
                          this.getPropertyValue(entity, 'Name') || 
                          this.getPropertyValue(entity, 'Tag') ||
                          `${typeName} ${entityID}`
              
              typeGroup.push({
                expressID: entityID,
                name: name,
                type: typeName,
                children: [],
                properties: entity
              })
              existingIDs.add(entityID)
            } catch (err) {
              // 忽略单个实体错误
            }
          }
          
          if (typeGroup.length > 0) {
            if (typeGroup.length === 1) {
              items.push(...typeGroup)
            } else {
              items.push({
                expressID: 0,
                name: `${typeName} (${typeGroup.length})`,
                type: 'IFCCategory',
                children: typeGroup
              })
            }
          }
        } catch (err) {
          // 忽略类型错误
        }
      }
      
      console.log(`获取到 ${items.length} 个实体项`)
      return items
    } catch (err) {
      console.error('获取实体失败:', err)
      return []
    }
  }
  
  collectIDs(item, idSet) {
    if (item.expressID && item.expressID > 0) {
      idSet.add(item.expressID)
    }
    if (item.children && Array.isArray(item.children)) {
      item.children.forEach(child => this.collectIDs(child, idSet))
    }
  }
  
  getTypes(modelID, ifcAPI) {
    try {
      console.log('获取类型（Types）...')
      const items = []
      
      // IFC 类型对象类型
      const typeObjectTypes = [
        WebIFC.IFCPROPERTYSETTEMPLATE,
        WebIFC.IFCDOORTYPE,
        WebIFC.IFCWINDOWTYPE,
        WebIFC.IFCWALLTYPE,
        WebIFC.IFCSLABTYPE,
        WebIFC.IFCBEAMTYPE,
        WebIFC.IFCCOLUMNTYPE,
        WebIFC.IFCPRODUCTTYPE,
        WebIFC.IFCTYPEPRODUCT
      ]
      
      for (const typeObjectType of typeObjectTypes) {
        try {
          const typeIDs = ifcAPI.GetLineIDsWithType(modelID, typeObjectType)
          if (!typeIDs || typeIDs.length === 0) continue
          
          const typeName = this.getTypeName(typeObjectType)
          
          for (const typeID of typeIDs) {
            try {
              const typeObj = ifcAPI.GetLine(modelID, typeID)
              // 优先使用 value 属性
              const name = this.getPropertyValue(typeObj, 'value') ||
                          this.getPropertyValue(typeObj, 'Value') ||
                          this.getPropertyValue(typeObj, 'Name') || 
                          this.getPropertyValue(typeObj, 'Tag') ||
                          `${typeName} ${typeID}`
              
              items.push({
                expressID: typeID,
                name: name,
                type: typeName,
                children: [],
                properties: typeObj
              })
            } catch (err) {
              // 忽略单个类型错误
            }
          }
        } catch (err) {
          // 忽略类型错误
        }
      }
      
      console.log(`获取到 ${items.length} 个类型`)
      return items
    } catch (err) {
      console.error('获取类型失败:', err)
      return []
    }
  }
  
  getPropertySets(modelID, ifcAPI) {
    try {
      console.log('获取属性集（Property Sets）...')
      const items = []
      
      // 尝试获取 IFCPropertySet
      const propertySetType = WebIFC.IFCPROPERTYSET
      try {
        const propertySetIDs = ifcAPI.GetLineIDsWithType(modelID, propertySetType)
        
        for (const propertySetID of propertySetIDs) {
          try {
            const propertySet = ifcAPI.GetLine(modelID, propertySetID)
            // 优先使用 value 属性
            const name = this.getPropertyValue(propertySet, 'value') ||
                        this.getPropertyValue(propertySet, 'Value') ||
                        this.getPropertyValue(propertySet, 'Name') || 
                        this.getPropertyValue(propertySet, 'GlobalId') ||
                        `PropertySet ${propertySetID}`
            
            items.push({
              expressID: propertySetID,
              name: name,
              type: 'IFCPropertySet',
              children: [],
              properties: propertySet
            })
          } catch (err) {
            // 忽略单个属性集错误
          }
        }
      } catch (err) {
        console.warn('获取属性集失败:', err)
      }
      
      console.log(`获取到 ${items.length} 个属性集`)
      return items
    } catch (err) {
      console.error('获取属性集失败:', err)
      return []
    }
  }
  
  getQuantitySets(modelID, ifcAPI) {
    try {
      console.log('获取量集（Quantity Sets）...')
      const items = []
      
      // 尝试获取 IFCQuantitySet
      const quantitySetType = WebIFC.IFCELEMENTQUANTITY
      try {
        const quantitySetIDs = ifcAPI.GetLineIDsWithType(modelID, quantitySetType)
        
        for (const quantitySetID of quantitySetIDs) {
          try {
            const quantitySet = ifcAPI.GetLine(modelID, quantitySetID)
            // 优先使用 value 属性
            const name = this.getPropertyValue(quantitySet, 'value') ||
                        this.getPropertyValue(quantitySet, 'Value') ||
                        this.getPropertyValue(quantitySet, 'Name') || 
                        this.getPropertyValue(quantitySet, 'GlobalId') ||
                        `QuantitySet ${quantitySetID}`
            
            items.push({
              expressID: quantitySetID,
              name: name,
              type: 'IFCQuantitySet',
              children: [],
              properties: quantitySet
            })
          } catch (err) {
            // 忽略单个量集错误
          }
        }
      } catch (err) {
        console.warn('获取量集失败:', err)
      }
      
      console.log(`获取到 ${items.length} 个量集`)
      return items
    } catch (err) {
      console.error('获取量集失败:', err)
      return []
    }
  }
  
  getRules(modelID, ifcAPI) {
    try {
      console.log('获取规则（Rules）...')
      const items = []
      
      // IFC 中规则通常是约束或验证规则
      // 可能包含在某些约束对象中，但 web-ifc 可能没有直接的 IFCRule 类型
      // 这里可以扩展查找相关的约束对象
      
      // 尝试查找可能的规则相关对象
      // 注意：IFC 标准中规则通常嵌入在其他对象中，而不是独立存在
      
      console.log(`获取到 ${items.length} 个规则`)
      return items
    } catch (err) {
      console.error('获取规则失败:', err)
      return []
    }
  }
  
  getFunctions(modelID, ifcAPI) {
    try {
      console.log('获取函数（Functions）...')
      const items = []
      
      // IFC 中函数概念较少，可能包含一些计算方法或函数对象
      // 这里可以扩展获取相关的函数对象
      // 目前 IFC 标准中可能没有明确的函数对象类型
      
      console.log(`获取到 ${items.length} 个函数`)
      return items
    } catch (err) {
      console.error('获取函数失败:', err)
      return []
    }
  }
  
  getModelItemsFromScene() {
    if (!this.viewer) return []
    
    const viewer = this.viewer
    const scene = viewer.context?.getScene()
    
    if (!scene) {
      console.warn('场景不存在')
      return []
    }
    
      const items = []
    const itemMap = new Map()
    
    console.log('从场景遍历获取模型数据...')
    console.log('场景子对象数量:', scene.children?.length || 0)
    
    // 遍历场景，收集所有 IFC 对象
    let traverseCount = 0
      scene.traverse((child) => {
      traverseCount++
      
      // 检查多种可能的 IFC 对象标识方式
      const hasExpressID = child.userData && child.userData.expressID
      const hasIfcClass = child.userData && child.userData.ifcClass
      const hasModelID = child.userData && child.userData.modelID
      const hasIfcData = child.userData && (
        child.userData.category === 'IFC' ||
        child.userData.type?.includes('IFC') ||
        child.name?.includes('IFC')
      )
      
      if (hasExpressID || hasIfcClass || hasModelID || hasIfcData) {
        const expressID = child.userData?.expressID || child.userData?.id || traverseCount
        const name = child.name || 
                    child.userData?.name || 
                    child.userData?.LongName ||
                    child.userData?.label ||
                    `Item ${expressID}`
        const type = child.userData?.ifcClass || 
                    child.userData?.type ||
                    child.userData?.category ||
                    'Unknown'
        
        if (!itemMap.has(expressID)) {
          const item = {
            expressID: expressID,
            name: name,
            type: type,
            children: [],
            properties: child.userData
          }
          itemMap.set(expressID, item)
          items.push(item)
        }
      }
    })
    
    console.log(`遍历了 ${traverseCount} 个对象`)
    console.log(`从场景获取到 ${items.length} 个构件`)
    
    // 如果没有找到构件，尝试查找所有 Mesh 对象
    if (items.length === 0) {
      console.log('未找到 IFC 对象，尝试查找所有 Mesh...')
      scene.traverse((child) => {
        if (child.type === 'Mesh' || child.type === 'Group') {
          const expressID = child.id || Math.random() * 1000000
          const name = child.name || `Mesh ${expressID}`
          items.push({
            expressID: expressID,
            name: name,
            type: child.type,
            children: [],
            properties: child.userData
          })
        }
      })
      console.log(`找到 ${items.length} 个 Mesh 对象`)
    }
    
    return items
  }
  
  buildSpatialStructure(modelID, ifcAPI) {
    try {
      const items = []
      
      // 获取项目
      const projectIDs = ifcAPI.GetLineIDsWithType(modelID, WebIFC.IFCPROJECT)
      if (projectIDs.length === 0) {
        return this.getAllElements(modelID, ifcAPI)
      }
      
      for (const projectID of projectIDs) {
        const project = ifcAPI.GetLine(modelID, projectID)
        // 优先使用 value 属性
        const projectName = this.getPropertyValue(project, 'value') ||
                           this.getPropertyValue(project, 'Value') ||
                           this.getPropertyValue(project, 'Name') || 
                           this.getPropertyValue(project, 'LongName') ||
                           'Project'
        
        const projectItem = {
          expressID: projectID,
          name: projectName,
          type: 'IFCProject',
          children: [],
          properties: project
        }
        
        // 获取 Site
        const siteIDs = this.getRelatedItems(modelID, ifcAPI, projectID, WebIFC.IFCSITE)
        for (const siteID of siteIDs) {
          const site = ifcAPI.GetLine(modelID, siteID)
          // 优先使用 value 属性
          const siteName = this.getPropertyValue(site, 'value') ||
                          this.getPropertyValue(site, 'Value') ||
                          this.getPropertyValue(site, 'Name') || 
                          'Site'
          
          const siteItem = {
            expressID: siteID,
            name: siteName,
            type: 'IFCSite',
            children: [],
            properties: site
          }
          
          // 获取 Building
          const buildingIDs = this.getRelatedItems(modelID, ifcAPI, siteID, WebIFC.IFCBUILDING)
          for (const buildingID of buildingIDs) {
            const building = ifcAPI.GetLine(modelID, buildingID)
            // 优先使用 value 属性
            const buildingName = this.getPropertyValue(building, 'value') ||
                                this.getPropertyValue(building, 'Value') ||
                                this.getPropertyValue(building, 'Name') || 
                                'Building'
            
            const buildingItem = {
              expressID: buildingID,
              name: buildingName,
              type: 'IFCBuilding',
              children: [],
              properties: building
            }
            
            // 获取 BuildingStorey
            const storeyIDs = this.getRelatedItems(modelID, ifcAPI, buildingID, WebIFC.IFCBUILDINGSTOREY)
            for (const storeyID of storeyIDs) {
              const storey = ifcAPI.GetLine(modelID, storeyID)
              // 优先使用 value 属性，直接使用，不做额外处理
              let storeyName = ''
              
              // 检查 value 属性
              if (storey.value !== undefined && storey.value !== null) {
                if (typeof storey.value === 'string') {
                  // 如果 value 是字符串（如 "1F 0.00"），直接使用
                  storeyName = storey.value
                } else if (typeof storey.value === 'object') {
                  // 如果是对象，尝试获取其 value 属性
                  storeyName = storey.value.value || storey.value.Name || storey.value.name || String(storey.value)
                } else {
                  storeyName = String(storey.value)
                }
              } else {
                // 回退到其他属性
                storeyName = this.getPropertyValue(storey, 'Value') ||
                            this.getPropertyValue(storey, 'Name') || 
                            this.getPropertyValue(storey, 'LongName') ||
                            'Storey'
              }
              
              // 提取高度（如果需要，但优先使用 value 中的信息）
              let elevation = null
              try {
                // 如果 value 中已经包含高度信息（如 "1F 0.00"），尝试提取
                if (storeyName && /\d+\.?\d*/.test(storeyName)) {
                  const elevationMatch = storeyName.match(/\d+\.?\d*/)
                  if (elevationMatch) {
                    elevation = parseFloat(elevationMatch[0])
                  }
                }
                
                // 如果没有从 value 中提取到，尝试从其他属性获取
                if (elevation === null) {
                  elevation = this.getPropertyValue(storey, 'Elevation')
                  if (elevation === null || elevation === undefined) {
                    elevation = this.getPropertyValue(storey, 'elevation')
                  }
                  if (elevation === null || elevation === undefined) {
                    const placement = this.getPropertyValue(storey, 'ElevationOfRefHeight')
                    if (placement !== null && placement !== undefined) {
                      elevation = placement
                    }
                  }
                }
              } catch (err) {
                console.warn(`获取楼层 ${storeyID} 高度失败:`, err)
              }
              
              // 直接使用 storeyName（value 的值），不修改
              const storeyItem = {
                expressID: storeyID,
                name: storeyName, // 使用实际的 value，如 "1F 0.00"
                type: 'IFCBuildingStorey',
                elevation: elevation,
                properties: storey,
                children: []
              }
              
              // 获取空间和元素
              const spaceIDs = this.getRelatedItems(modelID, ifcAPI, storeyID, WebIFC.IFCSPACE)
              const elementIDs = this.getRelatedItems(modelID, ifcAPI, storeyID, WebIFC.IFCBUILDINGELEMENT)
              
              // 添加空间（保持简单结构）
              for (const spaceID of spaceIDs) {
                const space = ifcAPI.GetLine(modelID, spaceID)
                // 优先使用 value 属性
                const spaceName = this.getPropertyValue(space, 'value') ||
                                 this.getPropertyValue(space, 'Value') ||
                                 this.getPropertyValue(space, 'Name') || 
                                 `Space ${spaceID}`
                storeyItem.children.push({
                  expressID: spaceID,
                  name: spaceName,
                  type: 'IFCSpace',
                  children: [],
                  properties: space
                })
              }
              
              // 按层级结构组织元素：楼层 -> IFC类型 -> 具体分类 -> 实例
              // 第一步：按 IFC 类型分组（如 IfcWall, IfcDoor 等）
              const elementsByType = new Map()
              
              console.log(`[buildSpatialStructure] 处理楼层 ${storeyName} 下的 ${elementIDs.length} 个元素`)
              
              for (const elementID of elementIDs) {
                try {
                  const element = ifcAPI.GetLine(modelID, elementID)
                  const elementType = this.getIfcType(ifcAPI, modelID, elementID)
                  
                  // 获取元素名称（优先使用 value）
                  const elementName = this.getPropertyValue(element, 'value') ||
                                     this.getPropertyValue(element, 'Value') ||
                                     this.getPropertyValue(element, 'Name') || 
                                     this.getPropertyValue(element, 'Tag') ||
                                     `${elementType} ${elementID}`
                  
                  // 获取元素的具体分类（如 "基本墙:加气混凝土砌块内"）
                  // 这通常存储在 Type 属性或关联的 TypeObject 中
                  let typeCategory = ''
                  try {
                    // 方法1：尝试从 Type 属性获取
                    const typeRelation = this.getPropertyValue(element, 'IsTypedBy')
                    if (typeRelation && Array.isArray(typeRelation) && typeRelation.length > 0) {
                      const typeRelID = typeRelation[0]
                      const typeRel = ifcAPI.GetLine(modelID, typeRelID)
                      const relatingType = this.getPropertyValue(typeRel, 'RelatingType')
                      if (relatingType) {
                        const typeObj = ifcAPI.GetLine(modelID, relatingType)
                        typeCategory = this.getPropertyValue(typeObj, 'value') ||
                                     this.getPropertyValue(typeObj, 'Value') ||
                                     this.getPropertyValue(typeObj, 'Name') || 
                                     ''
                      }
                    }
                    
                    // 方法2：尝试从属性集中获取类型信息（如 Psets 中的类型描述）
                    if (!typeCategory) {
                      const psets = this.getPropertyValue(element, 'IsDefinedBy')
                      if (psets && Array.isArray(psets)) {
                        for (const psetRefID of psets) {
                          try {
                            const psetRef = ifcAPI.GetLine(modelID, psetRefID)
                            const pset = this.getPropertyValue(psetRef, 'RelatingPropertyDefinition')
                            if (pset) {
                              const psetObj = ifcAPI.GetLine(modelID, pset)
                              const psetType = ifcAPI.GetLineType(modelID, pset)
                              if (psetType === WebIFC.IFCPROPERTYSET) {
                                const props = this.getPropertyValue(psetObj, 'HasProperties') || []
                                for (const propRefID of props) {
                                  try {
                                    const propRef = ifcAPI.GetLine(modelID, propRefID)
                                    const prop = this.getPropertyValue(propRef, 'RelatingPropertyDefinition')
                                    if (prop) {
                                      const propObj = ifcAPI.GetLine(modelID, prop)
                                      const propName = this.getPropertyValue(propObj, 'Name')
                                      const propValue = this.getPropertyValue(propObj, 'NominalValue')
                                      if (propName && (propName.toLowerCase().includes('type') || 
                                                       propName.toLowerCase().includes('类型'))) {
                                        typeCategory = propValue?.value || propValue?.Value || propValue || typeCategory
                                        break
                                      }
                                    }
                                  } catch (e) {
                                    // 忽略
                                  }
                                }
                              }
                            }
                          } catch (e) {
                            // 忽略
                          }
                        }
                      }
                    }
                    
                    // 方法3：尝试从 Name 或 Tag 中提取类型信息（如 "墙-200:1029942" 中的 "墙-200"）
                    if (!typeCategory) {
                      const tag = this.getPropertyValue(element, 'Tag')
                      if (tag && typeof tag === 'string' && tag.includes(':')) {
                        const parts = tag.split(':')
                        if (parts.length > 1) {
                          typeCategory = parts[0].trim()
                        }
                      }
                    }
                    
                    // 方法4：尝试从 LongName 或其他属性获取
                    if (!typeCategory) {
                      const longName = this.getPropertyValue(element, 'LongName')
                      if (longName && typeof longName === 'string') {
                        // 如果 LongName 包含类型信息，使用它
                        typeCategory = longName
                      }
                    }
                  } catch (err) {
                    console.warn(`获取元素 ${elementID} 的类型分类失败:`, err)
                  }
                  
                  const elementNode = {
                    expressID: elementID,
                    name: elementName,
                    type: elementType,
                    children: [],
                    properties: element
                  }
                  
                  // 按 IFC 类型分组
                  if (!elementsByType.has(elementType)) {
                    elementsByType.set(elementType, [])
                  }
                  
                  // 如果有类型分类，创建嵌套结构：IFC类型 -> 类型分类 -> 实例
                  if (typeCategory && typeCategory.trim()) {
                    // 查找是否已有该类型分类的组
                    const typeGroup = elementsByType.get(elementType)
                    let categoryGroup = typeGroup.find((g) => g.name === typeCategory && g.type === 'IFCCategory')
                    
                    if (!categoryGroup) {
                      // 创建新的类型分类组（如 "基本墙:加气混凝土砌块内"）
                      categoryGroup = {
                        expressID: 0,
                        name: typeCategory,
                        type: 'IFCCategory',
                        children: []
                      }
                      typeGroup.push(categoryGroup)
                      console.log(`[buildSpatialStructure] 创建类型分类组: ${typeCategory} (在 ${elementType} 下)`)
                    }
                    
                    // 将元素添加到类型分类组中
                    categoryGroup.children.push(elementNode)
                  } else {
                    // 没有类型分类，直接添加到 IFC 类型组（但会被IFC类型组节点包装）
                    elementsByType.get(elementType).push(elementNode)
                  }
                } catch (err) {
                  console.warn(`处理元素 ${elementID} 失败:`, err)
                }
              }
              
              // 将分组后的元素添加到楼层节点
              // 始终创建 IFC 类型组节点（如 IfcWall, IfcDoor 等），以保持层级结构：楼层 -> IFC类型 -> 类型分类 -> 实例
              console.log(`[buildSpatialStructure] 楼层 ${storeyName} 下共有 ${elementsByType.size} 个 IFC 类型组`)
              
              for (const [ifcType, elements] of elementsByType) {
                if (elements.length > 0) {
                  // 总是创建 IFC 类型组节点，即使只有一个元素
                  const typeGroupNode = {
                    expressID: 0,
                    name: ifcType,
                    type: 'IFCCategory',
                    children: elements,
                    properties: {}
                  }
                  storeyItem.children.push(typeGroupNode)
                  console.log(`[buildSpatialStructure] ✅ 创建 IFC 类型组: ${ifcType}, 包含 ${elements.length} 个子项`)
                  
                  // 调试：输出类型分类组的信息
                  const categoryGroups = elements.filter((e) => e.type === 'IFCCategory')
                  const directElements = elements.filter((e) => e.type !== 'IFCCategory')
                  if (categoryGroups.length > 0) {
                    console.log(`  - 有 ${categoryGroups.length} 个类型分类组:`, categoryGroups.map((g) => g.name))
                  }
                  if (directElements.length > 0) {
                    console.log(`  - 有 ${directElements.length} 个直接元素（无类型分类）`)
                  }
                }
              }
              
              console.log(`[buildSpatialStructure] 楼层 ${storeyName} 最终有 ${storeyItem.children.length} 个子节点`)
              
              buildingItem.children.push(storeyItem)
            }
            
            siteItem.children.push(buildingItem)
          }
          
          projectItem.children.push(siteItem)
        }
        
        items.push(projectItem)
      }
      
      return items
    } catch (err) {
      console.error('构建空间结构失败:', err)
      return this.getAllElements(modelID, ifcAPI)
    }
  }
  
  getAllElements(modelID, ifcAPI) {
    try {
      console.log(`开始获取模型 ${modelID} 的所有元素...`)
      const items = []
      const itemMap = new Map()
      
      // 获取所有常见的 IFC 元素类型
      const elementTypes = [
        WebIFC.IFCPROJECT,
        WebIFC.IFCSITE,
        WebIFC.IFCBUILDING,
        WebIFC.IFCBUILDINGSTOREY,
        WebIFC.IFCSPACE,
        WebIFC.IFCWALL,
        WebIFC.IFCWALLSTANDARDCASE,
        WebIFC.IFCSLAB,
        WebIFC.IFCROOF,
        WebIFC.IFCDOOR,
        WebIFC.IFCWINDOW,
        WebIFC.IFCCOLUMN,
        WebIFC.IFCBEAM,
        WebIFC.IFCSTAIR,
        WebIFC.IFCBUILDINGELEMENTPROXY,
        WebIFC.IFCBUILDINGELEMENT
      ]
      
      // 按类型分组
      const typeGroups = new Map()
      let totalElements = 0
      
      for (const elementType of elementTypes) {
        try {
          const elementIDs = ifcAPI.GetLineIDsWithType(modelID, elementType)
          if (!elementIDs || elementIDs.length === 0) continue
          
          const typeName = this.getTypeName(elementType)
          console.log(`找到 ${elementIDs.length} 个 ${typeName}`)
          
          for (const elementID of elementIDs) {
            try {
              const element = ifcAPI.GetLine(modelID, elementID)
              // 优先使用 value 属性
              const name = this.getPropertyValue(element, 'value') ||
                          this.getPropertyValue(element, 'Value') ||
                          this.getPropertyValue(element, 'Name') || 
                          this.getPropertyValue(element, 'Tag') ||
                          this.getPropertyValue(element, 'LongName') ||
                          this.getPropertyValue(element, 'GlobalId') ||
                          `${typeName} ${elementID}`
              
              if (!typeGroups.has(typeName)) {
                typeGroups.set(typeName, [])
              }
              
              typeGroups.get(typeName).push({
                expressID: elementID,
                name: name,
                type: typeName,
                children: [],
                properties: element
              })
              totalElements++
            } catch (err) {
              // 忽略单个元素错误
            }
          }
        } catch (err) {
          // 忽略类型错误
        }
      }
      
      console.log(`按类型分组获取到 ${typeGroups.size} 个类别，共 ${totalElements} 个元素`)
      
      // 如果按类型分组有结果，组织成树形结构
      if (typeGroups.size > 0) {
        for (const [typeName, elements] of typeGroups) {
          if (elements.length > 0) {
            if (elements.length === 1 && !['IFCProject', 'IFCSite', 'IFCBuilding'].includes(typeName)) {
              // 如果只有一个元素，直接显示，不分组
              items.push(...elements)
            } else {
              // 多个元素按类型分组
              items.push({
                expressID: 0,
                name: `${typeName} (${elements.length})`,
                type: 'Category',
                children: elements
              })
            }
          }
        }
        
        console.log(`最终返回 ${items.length} 个顶层项目`)
        return items
      }
      
      // 如果按类型分组没有结果，获取所有 PRODUCT 类型
      console.log('按类型分组无结果，尝试获取所有 PRODUCT...')
      try {
        const allProducts = ifcAPI.GetLineIDsWithType(modelID, WebIFC.IFCPRODUCT)
        console.log(`找到 ${allProducts.length} 个 PRODUCT`)
        
        if (allProducts && allProducts.length > 0) {
          const allItems = []
          const maxItems = Math.min(allProducts.length, 5000) // 限制最多5000个
          
          for (let i = 0; i < maxItems; i++) {
            const elementID = allProducts[i]
            try {
              const element = ifcAPI.GetLine(modelID, elementID)
              const type = this.getIfcType(ifcAPI, modelID, elementID)
              // 优先使用 value 属性
              const name = this.getPropertyValue(element, 'value') ||
                          this.getPropertyValue(element, 'Value') ||
                          this.getPropertyValue(element, 'Name') || 
                          this.getPropertyValue(element, 'Tag') ||
                          this.getPropertyValue(element, 'LongName') ||
                          `${type} ${elementID}`
              
              allItems.push({
                expressID: elementID,
                name: name,
                type: type,
                children: [],
                properties: element
              })
            } catch (err) {
              // 忽略单个元素错误
            }
          }
          
          console.log(`成功获取 ${allItems.length} 个元素`)
          return allItems
        }
      } catch (err) {
        console.error('获取 PRODUCT 失败:', err)
      }
      
      console.warn('无法获取任何元素')
      return []
    } catch (err) {
      console.error('获取所有元素失败:', err)
      return []
    }
  }
  
  getRelatedItems(modelID, ifcAPI, parentID, targetType) {
    try {
      const parent = ifcAPI.GetLine(modelID, parentID)
      const isDecomposedBy = this.getPropertyValue(parent, 'IsDecomposedBy')
      
      if (!isDecomposedBy || !Array.isArray(isDecomposedBy)) {
        return []
      }
      
      const relatedItems = []
      
      for (const relID of isDecomposedBy) {
        try {
          const relDef = ifcAPI.GetLine(modelID, relID)
          const relatedObjects = this.getPropertyValue(relDef, 'RelatedObjects') || []
          
          for (const objID of relatedObjects) {
            const obj = ifcAPI.GetLine(modelID, objID)
            const objType = ifcAPI.GetLineType(modelID, objID)
            
            if (objType === targetType) {
              relatedItems.push(objID)
            }
          }
        } catch (err) {
          // 忽略单个关系错误
        }
      }
      
      return relatedItems
    } catch (err) {
      return []
    }
  }
  
  getPropertyValue(obj, propName) {
    if (!obj) return null
    
    // 尝试多种属性访问方式
    // 首先尝试直接访问
    if (obj[propName] !== undefined && obj[propName] !== null) {
      return obj[propName]
    }
    
    // 尝试大小写变体
    if (obj[propName.toLowerCase()] !== undefined && obj[propName.toLowerCase()] !== null) {
      return obj[propName.toLowerCase()]
    }
    
    if (obj[propName.toUpperCase()] !== undefined && obj[propName.toUpperCase()] !== null) {
      return obj[propName.toUpperCase()]
    }
    
    // 尝试从 value 对象中获取
    if (obj.value && typeof obj.value === 'object') {
      if (obj.value[propName] !== undefined && obj.value[propName] !== null) {
        return obj.value[propName]
      }
      if (obj.value[propName.toLowerCase()] !== undefined && obj.value[propName.toLowerCase()] !== null) {
        return obj.value[propName.toLowerCase()]
      }
    }
    
    // 如果是 Name 属性，尝试获取 value（如果 value 是字符串）
    if (propName === 'Name' || propName === 'name') {
      if (obj.value !== undefined && obj.value !== null) {
        // 如果 value 是字符串，直接返回
        if (typeof obj.value === 'string') {
          return obj.value
        }
        // 如果 value 是对象，尝试获取其 value 属性
        if (typeof obj.value === 'object' && obj.value.value !== undefined) {
          return obj.value.value
        }
      }
    }
    
    return null
  }
  
  getIfcType(ifcAPI, modelID, elementID) {
    try {
      const typeID = ifcAPI.GetLineType(modelID, elementID)
      return this.getTypeName(typeID) || 'Unknown'
    } catch {
      return 'Unknown'
    }
  }
  
  getTypeName(typeID) {
    const typeMap = {
      [WebIFC.IFCPROJECT]: 'IFCProject',
      [WebIFC.IFCSITE]: 'IFCSite',
      [WebIFC.IFCBUILDING]: 'IFCBuilding',
      [WebIFC.IFCBUILDINGSTOREY]: 'IFCBuildingStorey',
      [WebIFC.IFCSPACE]: 'IFCSpace',
      [WebIFC.IFCWALL]: 'IFCWall',
      [WebIFC.IFCWALLSTANDARDCASE]: 'IFCWallStandardCase',
      [WebIFC.IFCSLAB]: 'IFCSlab',
      [WebIFC.IFCROOF]: 'IFCRoof',
      [WebIFC.IFCDOOR]: 'IFCDoor',
      [WebIFC.IFCWINDOW]: 'IFCWindow',
      [WebIFC.IFCCOLUMN]: 'IFCColumn',
      [WebIFC.IFCBEAM]: 'IFCBeam',
      [WebIFC.IFCSTAIR]: 'IFCStair',
      [WebIFC.IFCBUILDINGELEMENTPROXY]: 'IFCBuildingElementProxy',
      [WebIFC.IFCBUILDINGELEMENT]: 'IFCBuildingElement',
      [WebIFC.IFCPRODUCT]: 'IFCProduct',
      [WebIFC.IFCPROPERTYSET]: 'IFCPropertySet',
      [WebIFC.IFCELEMENTQUANTITY]: 'IFCElementQuantity',
      [WebIFC.IFCPROPERTYSETTEMPLATE]: 'IFCPropertySetTemplate',
      [WebIFC.IFCDOORTYPE]: 'IFCDoorType',
      [WebIFC.IFCWINDOWTYPE]: 'IFCWindowType',
      [WebIFC.IFCWALLTYPE]: 'IFCWallType',
      [WebIFC.IFCSLABTYPE]: 'IFCSlabType',
      [WebIFC.IFCBEAMTYPE]: 'IFCBeamType',
      [WebIFC.IFCCOLUMNTYPE]: 'IFCColumnType',
      [WebIFC.IFCPRODUCTTYPE]: 'IFCProductType',
      [WebIFC.IFCTYPEPRODUCT]: 'IFCTypeProduct',
      [WebIFC.IFCTYPEOBJECT]: 'IFCTypeObject'
    }
    
    return typeMap[typeID] || `Type${typeID}`
  }
  
  getProperties(expressID) {
    if (!this.viewer) return null
    
    try {
      const ifcManager = this.viewer.IFC
      if (ifcManager && ifcManager.GetLineIDsWithType) {
        return ifcManager.GetLineIDsWithType(0, WebIFC.IFCPROPERTYSET)
      }
    } catch {
      return null
    }
    return null
  }
  
  /**
   * 启用选择模式（根据文档要求）
   */
  enableSelectionMode() {
    if (!this.viewer) return
    
    // 如果高亮功能未启用，不启用选择模式（优化效率）
    if (!this.highlightEnabled) {
      return
    }
    
    try {
      const ifcManager = this.viewer.IFC
      if (ifcManager && ifcManager.selector) {
        // 启用选择模式（文档推荐）
        if (ifcManager.selector.pickIfcItem) {
          ifcManager.selector.pickIfcItem()
          console.log('✓ 选择模式已启用')
        }
      }
    } catch (err) {
      console.warn('启用选择模式失败:', err)
    }
  }
  
  async pick(event) {
    if (!this.viewer) return null
    
    // 如果高亮功能未启用，不拾取元素（优化效率）
    if (!this.highlightEnabled) {
      return null
    }
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      
      if (!ifcManager) {
        console.warn('IFC 管理器不存在')
        return null
      }
      
      // 方法1：使用 selector.selection 中的 pick 方法（用户提供的正确位置）
      if (ifcManager.selector && ifcManager.selector.selection) {
        try {
          // 确保选择模式已启用（文档要求）
          if (ifcManager.selector.pickIfcItem && typeof ifcManager.selector.pickIfcItem === 'function') {
            try {
              ifcManager.selector.pickIfcItem()
            } catch (e) {
              // 忽略，可能已经启用
            }
          }
          
          // 使用 selector.selection.pick 方法（异步方法）
          const result = await ifcManager.selector.selection.pick(event)
          
          console.log('selector.selection.pick 返回结果:', result)
          
          if (result) {
            // 处理不同的返回格式
            let expressID = null
            let returnData = result
            
            // 如果返回的是数组
            if (Array.isArray(result) && result.length > 0) {
              const first = result[0]
              expressID = first.expressID || first.id || (typeof first === 'number' ? first : null)
              returnData = first
            }
            // 如果返回的是对象
            else if (typeof result === 'object' && result !== null) {
              expressID = result.expressID || result.id
            }
            // 如果返回的是数字
            else if (typeof result === 'number') {
              expressID = result
            }
            
            if (expressID) {
              console.log('✓ selector.selection.pick 成功，expressID:', expressID)
              return {
                expressID: expressID,
                type: returnData.type || returnData.ifcClass || 'Unknown',
                name: returnData.name || `Element ${expressID}`,
                object: returnData.object || null
              }
            }
            
            // 如果返回了结果但没有 expressID，直接返回
            console.log('selector.selection.pick 返回了结果但没有 expressID:', result)
            return result
          } else {
            console.log('selector.selection.pick 返回 null，尝试其他方法')
          }
        } catch (err) {
          console.log('selector.selection.pick 调用失败:', err.message)
        }
      }
      
      // 方法2：尝试其他可能的 pick 方法位置
      // if (ifcManager.selector) {
      //   const pickMethods = [
      //     () => ifcManager.selector.pick?.(event),
      //     () => ifcManager.selector.select?.(event),
      //     () => ifcManager.pick?.(event)
      //   ]
        
      //   for (const method of pickMethods) {
      //     try {
      //       const result = method()
      //       if (result) {
      //         return result
      //       }
      //     } catch (err) {
      //       // 继续尝试下一个方法
      //     }
      //   }
      // }
      
      // 方法2：使用射线检测手动拾取
      // try {
      //   const scene = viewer.context?.getScene()
      //   const camera = viewer.context?.ifcCamera?.camera || viewer.context?.camera
      //   const renderer = viewer.context?.renderer

      //   if (!scene || !camera) {
      //     console.warn('场景或相机不存在')
      //     return null
      //   }

      //   // 获取鼠标位置（归一化坐标）
      //   const rect = event.target.getBoundingClientRect()
      //   const mouseX = ((event.clientX - rect.left) / rect.width) * 2 - 1
      //   const mouseY = -((event.clientY - rect.top) / rect.height) * 2 + 1

      //   // 使用 Three.js 射线检测
      //   // 尝试从多个位置获取 Three.js
      //   let THREE = null
      //   let Raycaster = null

      //   // 尝试从不同位置获取 Three.js
      //   const threeSources = [
      //     window.THREE,
      //     viewer.THREE,
      //     viewer.context?.THREE,
      //     viewer.context?.renderer?.THREE,
      //     // 尝试从场景对象获取（Three.js 对象通常有 constructor）
      //     scene?.constructor?.Raycaster ? scene.constructor : null
      //   ]

      //   for (const source of threeSources) {
      //     if (source && source.Raycaster) {
      //       THREE = source
      //       Raycaster = source.Raycaster
      //       break
      //     }
      //   }

      //   // 如果还是找不到，尝试通过已知的 Three.js 对象获取
      //   if (!Raycaster && scene.children.length > 0) {
      //     const firstChild = scene.children[0]
      //     if (firstChild && firstChild.constructor) {
      //       const parentClass = firstChild.constructor
      //       if (parentClass.Raycaster) {
      //         THREE = parentClass
      //         Raycaster = parentClass.Raycaster
      //       }
      //     }
      //   }

      //   if (!Raycaster) {
      //     console.warn('无法找到 Three.js Raycaster')
      //     return null
      //   }

      //   const raycaster = new Raycaster()
      //   raycaster.setFromCamera({ x: mouseX, y: mouseY }, camera)

      //   // 检测与 IFC 对象的交集
      //   const intersects = raycaster.intersectObjects(scene.children, true)

      //   // 查找第一个有 expressID 的对象
      //   for (const intersect of intersects) {
      //     const object = intersect.object

      //     // 检查对象或其父对象是否有 expressID
      //     let currentObject = object
      //     while (currentObject) {
      //       if (currentObject.userData && currentObject.userData.expressID) {
      //         const expressID = currentObject.userData.expressID
      //         const ifcClass = currentObject.userData.ifcClass || currentObject.userData.type || 'Unknown'
      //         const name = currentObject.name ||
      //                     currentObject.userData.name ||
      //                     currentObject.userData.LongName ||
      //                     `${ifcClass} ${expressID}`

      //         return {
      //           expressID: expressID,
      //           type: ifcClass,
      //           name: name,
      //           object: currentObject,
      //           distance: intersect.distance
      //         }
      //       }
      //       currentObject = currentObject.parent
      //     }
      //   }

      //   console.log('未找到 IFC 对象')
      //   return null
      // } catch (err) {
      //   console.error('射线检测失败:', err)
      // }
      
      // 方法3：尝试使用 viewer 的拾取方法
      // try {
      //   if (viewer.castRay) {
      //     const rect = event.target.getBoundingClientRect()
      //     const mouseX = ((event.clientX - rect.left) / rect.width) * 2 - 1
      //     const mouseY = -((event.clientY - rect.top) / rect.height) * 2 + 1
      //     const result = viewer.castRay({ x: mouseX, y: mouseY })
      //     if (result) {
      //       return result
      //     }
      //   }
      // } catch (err) {
      //   console.warn('方法3失败:', err)
      // }
      
      console.warn('拾取失败，所有方法都尝试过了')
      return null
    } catch (err) {
      console.error('拾取失败:', err)
      return null
    }
  }
  
  /**
   * 高亮边框（金黄色边框高亮）- 优化版本，复用材质和对象
   * @param {Array<number>} items - expressID数组
   */
  highlightEdges(items) {
    if (!this.viewer || !this.currentModelId) return
    
    // 如果高亮功能未启用，不执行高亮（优化效率）
    if (!this.highlightEnabled) {
      return
    }
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      
      if (!ifcManager || !ifcManager.selector) {
        return
      }
      
      const scene = viewer.context?.getScene?.()
      if (!scene) return
      
      // 获取 THREE.js
      let THREE = null
      if (scene.constructor && scene.constructor.Group) {
        THREE = scene.constructor
      } else if (scene.children.length > 0 && scene.children[0].constructor) {
        THREE = scene.children[0].constructor
      } else if (typeof window !== 'undefined' && window.THREE) {
        THREE = window.THREE
      }
      
      if (!THREE || !THREE.Group || !THREE.EdgesGeometry || !THREE.LineSegments || !THREE.LineBasicMaterial) {
        return
      }
      
      // 创建高亮边框组（只创建一次）
      if (!this.highlightGroup) {
        this.highlightGroup = new THREE.Group()
        this.highlightGroup.name = 'HighlightEdges'
        scene.add(this.highlightGroup)
      }
      
      // 复用边框材质（只创建一次）
      if (!this.edgeMaterial) {
        this.edgeMaterial = new THREE.LineBasicMaterial({
          color: 0xffd700, // 金黄色
          linewidth: 3,
          depthTest: false,
          depthWrite: false
        })
      }
      
      // 将 items 转换为 Set 以便快速查找
      const targetIds = new Set(items || [])
      
      // 需要移除的高亮（之前有但现在没有）
      const toRemove = []
      for (const child of this.highlightGroup.children) {
        const expressID = child.userData?.expressID
        if (expressID && !targetIds.has(expressID)) {
          toRemove.push(child)
        }
      }
      
      // 移除不需要的高亮
      for (const child of toRemove) {
        if (child.geometry) child.geometry.dispose()
        this.highlightGroup.remove(child)
        this.currentHighlightedIds.delete(child.userData?.expressID)
      }
      
      // 需要添加的高亮（现在有但之前没有）
      const toAdd = []
      for (const expressID of targetIds) {
        if (!this.currentHighlightedIds.has(expressID)) {
          toAdd.push(expressID)
        }
      }
      
      // 批量获取 mesh（避免重复遍历场景）
      if (toAdd.length > 0) {
        // 从缓存或场景中获取 mesh
        const meshesToAdd = []
        
        for (const expressID of toAdd) {
          let mesh = null
          
          // 先检查缓存
          if (this.meshCache.has(expressID)) {
            mesh = this.meshCache.get(expressID)
            // 验证 mesh 仍然有效
            if (!mesh.parent || !mesh.geometry) {
              this.meshCache.delete(expressID)
              mesh = null
            }
          }
          
          // 如果缓存中没有，尝试获取
          if (!mesh) {
            try {
              // 方法1：使用 selector.getMesh (文档推荐，最快)
              if (ifcManager.selector.getMesh) {
                mesh = ifcManager.selector.getMesh(this.currentModelId, expressID)
                if (mesh) {
                  this.meshCache.set(expressID, mesh)
                }
              }
            } catch (err) {
              // 忽略单个错误
            }
          }
          
          // 如果还是找不到，从场景中查找（较慢，尽量避免）
          if (!mesh && toAdd.length < 10) { // 只有少量元素时才遍历场景
            scene.traverse((object) => {
              if (object.userData && object.userData.expressID === expressID && object.type === 'Mesh') {
                mesh = object
                this.meshCache.set(expressID, mesh)
                return false // 找到后停止遍历
              }
            })
          }
          
          if (mesh && mesh.geometry) {
            meshesToAdd.push({ expressID, mesh })
          }
        }
        
        // 批量创建边框
        for (const { expressID, mesh } of meshesToAdd) {
          try {
            // 创建边框几何体
            const edgesGeometry = new THREE.EdgesGeometry(mesh.geometry)
            const edges = new THREE.LineSegments(edgesGeometry, this.edgeMaterial)
            
            // 使用世界矩阵确保边框位置正确
            edges.applyMatrix4(mesh.matrixWorld)
            edges.visible = true
            edges.renderOrder = 999
            
            edges.userData.expressID = expressID
            edges.userData.originalMesh = mesh
            
            this.highlightGroup.add(edges)
            this.currentHighlightedIds.add(expressID)
          } catch (err) {
            console.warn(`创建边框失败 (expressID: ${expressID}):`, err)
          }
        }
      }
      
      // 更新已存在边框的位置（如果 mesh 变换了）
      if (toAdd.length === 0 && toRemove.length === 0 && this.highlightGroup.children.length > 0) {
        // 只有在没有添加/删除时才更新位置（减少计算）
        for (const child of this.highlightGroup.children) {
          const originalMesh = child.userData?.originalMesh
          if (originalMesh && originalMesh.matrixWorld) {
            child.matrix.copy(originalMesh.matrixWorld)
          }
        }
      }
    } catch (err) {
      console.error('高亮边框失败:', err)
    }
  }
  
  /**
   * 清除边框高亮
   */
  clearHighlightEdges() {
    if (this.highlightGroup) {
      while (this.highlightGroup.children.length > 0) {
        const child = this.highlightGroup.children[0]
        if (child.geometry) child.geometry.dispose()
        if (child.material) child.material.dispose()
        this.highlightGroup.remove(child)
      }
    }
    this.currentHighlightedIds.clear()
  }
  
  highlight(items) {
    if (!this.viewer) return
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      
      if (!ifcManager) {
        console.warn('IFC 管理器不存在')
        return
      }
      
      // 方法1：使用 web-ifc-viewer 内置的 highlightIfcItems 方法（文档推荐）
      if (this.currentModelId !== null && viewer.highlightIfcItems) {
        try {
          viewer.highlightIfcItems(this.currentModelId, items)
          console.log('✓ 使用 highlightIfcItems 高亮成功')
          return
        } catch (err) {
          console.warn('highlightIfcItems 失败:', err)
        }
      }
      
      // 方法2：使用 selector.highlight
      if (ifcManager.selector) {
        const highlightMethods = [
          () => ifcManager.selector.highlight?.(items),
          () => ifcManager.selector.select?.(items),
          () => ifcManager.highlight?.(items),
          () => ifcManager.select?.(items)
        ]
        
        for (const method of highlightMethods) {
          try {
            if (method()) {
              console.log('高亮成功（方法2）')
              return
            }
          } catch (err) {
            // 继续尝试下一个方法
          }
        }
      }
      
      // 方法2：直接操作场景对象
      try {
        const scene = viewer.context?.getScene()
        if (scene) {
          // 先清除之前的高亮
          scene.traverse((child) => {
            if (child.userData && child.userData.isHighlighted) {
              // 恢复原始材质
              if (child.userData.originalMaterial) {
                child.material = child.userData.originalMaterial
              }
              child.userData.isHighlighted = false
            }
          })
          
          // 高亮新元素
          let highlightedCount = 0
          scene.traverse((child) => {
            if (child.userData && child.userData.expressID) {
              const expressID = child.userData.expressID
              if (items.includes(expressID)) {
                try {
                  // 保存原始材质
                  if (!child.userData.originalMaterial) {
                    child.userData.originalMaterial = child.material
                  }
                  
                  // 创建高亮材质（金黄色高亮）
                  if (child.material) {
                    const highlightColor = 0xffd700 // 金黄色
                    if (Array.isArray(child.material)) {
                      child.material = child.material.map(mat => {
                        const newMat = mat.clone()
                        newMat.emissive.setHex(highlightColor)
                        newMat.emissiveIntensity = 0.5
                        return newMat
                      })
                    } else {
                      const newMat = child.material.clone()
                      newMat.emissive.setHex(highlightColor)
                      newMat.emissiveIntensity = 0.5
                      child.material = newMat
                    }
                  }
                  
                  child.userData.isHighlighted = true
                  highlightedCount++
                } catch (err) {
                  console.warn(`高亮元素 ${expressID} 失败:`, err)
                }
              }
            }
          })
          
          if (highlightedCount > 0) {
            console.log(`成功高亮 ${highlightedCount} 个元素（方法2）`)
            // 更新渲染
            if (viewer.context?.renderer) {
              viewer.context.renderer.render(scene, viewer.context.ifcCamera?.camera || viewer.context.camera)
            }
            return
          }
        }
      } catch (err) {
        console.warn('方法2失败:', err)
      }
      
      // 方法3：使用 IFC 管理器的其他方法
      try {
        if (ifcManager.pick) {
          items.forEach(itemID => {
            try {
              ifcManager.pick(itemID)
            } catch (err) {
              // 忽略单个元素错误
            }
          })
          console.log('高亮成功（方法3）')
          return
        }
      } catch (err) {
        console.warn('方法3失败:', err)
      }
      
      console.warn('无法高亮元素，所有方法都失败')
    } catch (err) {
      console.error('高亮失败:', err)
    }
  }
  
  clearSelection() {
    if (!this.viewer) return
    
    try {
      const ifcManager = this.viewer.IFC
      if (ifcManager && ifcManager.selector && ifcManager.selector.unpick) {
        ifcManager.selector.unpick()
      }
    } catch (err) {
      console.error('清除选择失败:', err)
    }
  }
  
  isolate(items) {
    if (!this.viewer) return
    
    try {
      const ifcManager = this.viewer.IFC
      if (ifcManager && ifcManager.visibility) {
        ifcManager.visibility.hideAll()
        ifcManager.visibility.show(items, true)
      }
    } catch (err) {
      console.error('隔离失败:', err)
    }
  }
  
  showAll() {
    if (!this.viewer) return
    
    try {
      const ifcManager = this.viewer.IFC
      if (ifcManager && ifcManager.visibility && ifcManager.visibility.showAll) {
        ifcManager.visibility.showAll()
      }
    } catch (err) {
      console.error('显示全部失败:', err)
    }
  }
  
  hideAll() {
    if (!this.viewer) return
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      const scene = viewer.context?.getScene()
      
      // 方法1：尝试使用 ifcManager 的 hideAll API
      if (ifcManager && ifcManager.visibility) {
        if (ifcManager.visibility.hideAll) {
          ifcManager.visibility.hideAll()
          console.log('使用 hideAll API 隐藏所有元素')
          
          // 也直接隐藏所有 Mesh 对象以确保
          if (scene) {
            let count = 0
            scene.traverse((child) => {
              if ((child.type === 'Mesh' || child.type === 'Group') && child.visible !== false) {
                child.visible = false
                count++
              }
            })
            console.log(`同时隐藏 ${count} 个 Mesh 对象`)
          }
          return
        }
      }
      
      // 方法2：直接遍历场景隐藏所有对象
      if (scene) {
        let count = 0
        scene.traverse((child) => {
          // 隐藏所有 Mesh 和 Group 对象（这些通常是 IFC 模型）
          if (child.type === 'Mesh' || child.type === 'Group') {
            if (child.visible !== false) {
              child.visible = false
              count++
            }
          }
          // 也隐藏所有有 expressID 的对象
          else if (child.userData && child.userData.expressID) {
            child.visible = false
            count++
          } else if (child.expressID) {
            child.visible = false
            count++
          }
        })
        console.log(`直接隐藏场景中的 ${count} 个对象`)
      }
    } catch (err) {
      console.error('隐藏全部失败:', err)
    }
  }
  
  async show(items) {
    if (!this.viewer || !items || items.length === 0) return
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      
      if (!ifcManager) {
        console.warn('[show] ifcManager 不存在')
        return
      }
      
      // 获取模型ID（优先使用保存的 currentModelId，否则使用默认值 0）
      const modelID = this.currentModelId ?? 0
      
      // 优先使用官方推荐的 API：showByExpressIDs（批量操作，更高效）
      if (ifcManager.showByExpressIDs && typeof ifcManager.showByExpressIDs === 'function') {
        try {
          await ifcManager.showByExpressIDs(modelID, items)
          console.log(`[show] ✅ 使用 showByExpressIDs(${modelID}) 显示了 ${items.length} 个元素`)
          return // 成功，不需要继续
        } catch (err) {
          console.warn(`[show] showByExpressIDs(${modelID}) 失败:`, err?.message || err)
        }
      }
      
      // 回退到单个操作
      if (ifcManager.showByExpressID && typeof ifcManager.showByExpressID === 'function') {
        for (const expressID of items) {
          try {
            await ifcManager.showByExpressID(modelID, expressID)
          } catch (err) {
            console.warn(`[show] showByExpressID(${modelID}, ${expressID}) 失败:`, err?.message || err)
          }
        }
        console.log(`[show] ✅ 使用 showByExpressID(${modelID}) 显示了 ${items.length} 个元素`)
        return
      }
      
      // 回退到原来的方法
      await this.setVisibility(items, true)
    } catch (err) {
      console.error('显示元素失败:', err)
    }
  }
  
  async hide(items) {
    if (!this.viewer || !items || items.length === 0) return
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      
      if (!ifcManager) {
        console.warn('[hide] ifcManager 不存在')
        return
      }
      
      // 获取模型ID（优先使用保存的 currentModelId，否则使用默认值 0）
      const modelID = this.currentModelId ?? 0
      
      // 优先使用官方推荐的 API：hideByExpressIDs（批量操作，更高效）
      if (ifcManager.hideByExpressIDs && typeof ifcManager.hideByExpressIDs === 'function') {
        try {
          await ifcManager.hideByExpressIDs(modelID, items)
          console.log(`[hide] ✅ 使用 hideByExpressIDs(${modelID}) 隐藏了 ${items.length} 个元素`)
          return // 成功，不需要继续
        } catch (err) {
            console.warn(`[hide] hideByExpressIDs(${modelID}) 失败:`, err?.message || err)
        }
      }
      
      // 回退到单个操作
      if (ifcManager.hideByExpressID && typeof ifcManager.hideByExpressID === 'function') {
        for (const expressID of items) {
          try {
            await ifcManager.hideByExpressID(modelID, expressID)
          } catch (err) {
            console.warn(`[hide] hideByExpressID(${modelID}, ${expressID}) 失败:`, err?.message || err)
          }
        }
        console.log(`[hide] ✅ 使用 hideByExpressID(${modelID}) 隐藏了 ${items.length} 个元素`)
        return
      }
      
      // 回退到原来的方法
      await this.setVisibility(items, false)
    } catch (err) {
      console.error('隐藏元素失败:', err)
    }
  }
  
  async setVisibility(items, showItems) {
    if (!this.viewer || !items || items.length === 0) return
    
    try {
      const viewer = this.viewer
      const ifcManager = viewer.IFC
      
      if (!ifcManager) {
        console.warn('[setVisibility] ifcManager 不存在')
        return
      }
      
      // 获取模型ID（优先使用保存的 currentModelId，否则使用默认值 0）
      const modelID = this.currentModelId ?? 0
      
      // 优先使用官方推荐的 API：hideByExpressIDs/showByExpressIDs（批量操作，更高效）
      if (showItems) {
        if (ifcManager.showByExpressIDs && typeof ifcManager.showByExpressIDs === 'function') {
          try {
            await ifcManager.showByExpressIDs(modelID, items)
            return // 成功，不需要继续
          } catch (err) {
            console.warn(`[setVisibility] showByExpressIDs 失败:`, err?.message || err)
          }
        }
        
        // 回退到单个操作
        if (ifcManager.showByExpressID && typeof ifcManager.showByExpressID === 'function') {
          for (const expressID of items) {
            try {
              await ifcManager.showByExpressID(modelID, expressID)
            } catch (err) {
              console.warn(`[setVisibility] showByExpressID(${expressID}) 失败:`, err?.message || err)
            }
          }
          return
        }
      } else {
        if (ifcManager.hideByExpressIDs && typeof ifcManager.hideByExpressIDs === 'function') {
          try {
            await ifcManager.hideByExpressIDs(modelID, items)
            return // 成功，不需要继续
          } catch (err) {
            console.warn(`[setVisibility] hideByExpressIDs 失败:`, err?.message || err)
          }
        }
        
        // 回退到单个操作
        if (ifcManager.hideByExpressID && typeof ifcManager.hideByExpressID === 'function') {
          for (const expressID of items) {
            try {
              await ifcManager.hideByExpressID(modelID, expressID)
            } catch (err) {
              console.warn(`[setVisibility] hideByExpressID(${expressID}) 失败:`, err?.message || err)
            }
          }
          return
        }
      }
      
      // 如果官方API不可用，回退到场景遍历（不推荐，性能较差）
      console.warn('[setVisibility] 官方API不可用，回退到场景遍历方法')
      const scene = viewer.context?.getScene()
      if (scene) {
        const itemsSet = new Set(items)
        scene.traverse((child) => {
          const expressID = child.userData?.expressID || child.expressID || child.userData?.id
          if (expressID && itemsSet.has(expressID)) {
            child.visible = showItems
          }
        })
      }
    } catch (err) {
      console.error('[setVisibility] 设置可见性失败:', err)
    }
  }
}


